package com.jsg.sl651.entity.frame.body;

import com.jsg.sl651.constant.EncodingElementIdentifier;
import com.jsg.sl651.entity.data.Element;
import com.jsg.sl651.entity.data.Identifier;
import com.jsg.sl651.entity.station.RemoteTelemetryStationAddress;
import com.jsg.sl651.enums.CodingElementEnum;
import com.jsg.sl651.enums.CommunicationMessageType;
import com.jsg.sl651.exception.MessageBodyCodeException;
import com.jsg.sl651.util.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 根类
 */
@Getter
@Setter
@NoArgsConstructor
public abstract class MessageBody {

    protected final static String LOCAL_DATE_TIME_PATTERN = "yyyyMMddHHmmss";
    private static final String THIS_YEAR;

    static {
        THIS_YEAR = (LocalDateTime.now().getYear() / 100) + "";
    }

    // 消息流号
    protected int flowNumber;

    // 发报时间
    protected LocalDateTime sendTime;

    // 遥测站地址
    protected RemoteTelemetryStationAddress remoteTelemetryStationAddress;


    // 遥测站中包含的数据项目
    protected List<Element<?>> dataElements = new ArrayList<>();

    protected void addElement(Element<?> element) {
        dataElements.add(element);
    }


    public <T> Element<T> getElement(CommunicationMessageType type, byte[] keyBytes) {
        return getElement(type, ByteUtil.toHex(keyBytes));
    }
    public <T> Element<T> getElement(CommunicationMessageType type, String hexKey) {
        for (Element<?> dataElement : dataElements) {
            if (type == CommunicationMessageType.HEX) {
                if (dataElement.getHexKey().equals(hexKey)) {
                    return (Element<T>) dataElement;
                }
            } else {
                if (dataElement.getAsciiKey().equals(hexKey)) {
                    return (Element<T>) dataElement;
                }
            }
        }
        return null;
    }


    public <T> Element<T> getElement(CommunicationMessageType type, CodingElementEnum element) {
        String hexKey;
        if (type == CommunicationMessageType.HEX) {
            hexKey = ByteUtil.toHex(element.getHexBytes());
        } else {
            hexKey = ByteUtil.toHex(element.getAsciiBytes());
        }
        return getElement(type, hexKey);
    }


    protected MessageBody decodeBasic(byte[] hex) {
        return decodeBasic(ByteUtil.toHex(hex));
    }
    protected MessageBody decodeBasic(String hex) {
        if (hex.length() != 16) {
            throw new MessageBodyCodeException("流水号和发报时间解析失败，当前值： {}", hex);
        }
        this.flowNumber = Integer.parseInt(hex.substring(0, 4), 16);
        String timeStr =  THIS_YEAR + hex.substring(4,16);
        this.sendTime = LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_PATTERN));
        return this;
    }

    /**
     * 解析消息体
     * @param type 编码格式
     * @param bytes 消息体字节数组
     * @return MessageBody
     */
    public MessageBody decode(CommunicationMessageType type, byte[] bytes) throws MessageBodyCodeException {
        try {
            if (type == CommunicationMessageType.HEX) {
                return decodeHex(bytes);
            } else if (type == CommunicationMessageType.ASCII) {
                return decodeAscii(bytes);
            }
        } catch (Exception e) {
            throw new MessageBodyCodeException("消息体解析失败：{}", e.getMessage());
        }
        throw new MessageBodyCodeException("消息体解析失败，未知的编码格式");
    }

    /**
     * 获取消息体字节数组
     * @param type 编码格式
     * @return 需要发送的字节数组
     */
    public byte[] encode(CommunicationMessageType type) throws MessageBodyCodeException  {
        try {
            if (type == CommunicationMessageType.HEX) {
                return encodeHex();
            } else if (type == CommunicationMessageType.ASCII) {
                return encodeAscii();
            }
        } catch (Exception e) {
            throw new MessageBodyCodeException("消息体编码失败：{}", e.getMessage());
        }
        throw new MessageBodyCodeException("消息体编码失败，未知的编码格式");
    }

    public void parserElement(CommunicationMessageType type, ByteBuf buffer) {
        while (buffer.readableBytes() > 0) {
            Identifier identifier;
            if (type == CommunicationMessageType.HEX) {
                identifier = Identifier.createHex(buffer);
            } else {
                identifier = Identifier.createAscii(buffer);
            }
            Element<?> parser = EncodingElementIdentifier.parser(type,identifier);
            addElement(parser);
        }
    }

    protected ByteBuf toBuf(byte[] data) {
        return ByteBufAllocator.DEFAULT.buffer(data.length).writeBytes(data);
    }

    protected abstract MessageBody decodeHex(byte[] bytes) throws Exception;

    protected abstract MessageBody decodeAscii(byte[] bytes) throws Exception;

    protected abstract byte[] encodeHex() throws Exception;

    protected abstract byte[] encodeAscii()  throws Exception;

    public abstract int getFunctionCode();

}
